package com.yanggu.sa_token.demo_application.config;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import static com.yanggu.sa_token.demo_application.config.SaTokenExceptionHandler.Result.*;


/**
 * SaToken异常处理器
 *
 */
@Slf4j
@RestControllerAdvice
public class SaTokenExceptionHandler {

    @Autowired
    private HttpServletRequest request;

    /**
     * 认证失败
     */
    @ExceptionHandler(NotLoginException.class)
    public Result<Void> handleNotLoginException(NotLoginException exception) {
        log.error("认证失败, 请求方式: {}, 请求uri: {}, 异常message: {}",
                request.getMethod(), request.getRequestURI(), exception.getMessage(), exception);
        return fail(UNAUTHORIZED);
    }

    /**
     * 角色权限异常
     */
    @ExceptionHandler(NotRoleException.class)
    public Result<Void> handleNotRoleException(NotRoleException exception) {
        log.error("角色权限异常, 请求方式: {}, 请求uri: {}, 异常message: {}",
                request.getMethod(), request.getRequestURI(), exception.getMessage(), exception);
        return fail(FORBIDDEN);
    }

    /**
     * 权限码异常
     */
    @ExceptionHandler(NotPermissionException.class)
    public Result<Void> handleNotPermissionException(NotPermissionException exception) {
        log.error("权限码异常, 请求方式: {}, 请求uri: {}, 异常message: {}",
                request.getMethod(), request.getRequestURI(), exception.getMessage(), exception);
        return fail(FORBIDDEN);
    }

    @Data
    static class Result<T> {

        public static final int UNAUTHORIZED = 401;

        public static final int FORBIDDEN = 403;

        private Integer code;

        public static <T> Result<T> fail(int code) {
            Result<T> result = new Result<>();
            result.setCode(code);
            return result;
        }

    }

}
